#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"
using namespace std;

class Channals
{
public:
    Channals(int cntfd, int workid, int i)
        : _cntfd(cntfd), _workid(workid), _name("channals-" + to_string(i))
    {
    }

    int _cntfd;
    int _workid;
    string _name;
};

const static int num = 5;

void Work()
{
    while (true)
    {
        int mession = 0;
        ssize_t sz = read(0, &mession, sizeof(mession));
        if (sz == 0)
            break;
        else if (sz == 4)
            task.GetTask(mession)();
    }
    cout << "无任务，子进程退出" << endl;
}

void CreateChannals(vector<Channals> *channals)
{
    vector<int> temp;
    for (int i = 0; i < num; i++)
    {
        int pipefd[2];
        int pret = pipe(pipefd);
        assert(pret == 0);

        pid_t id = fork();
        assert(id != -1);
        if (id == 0)
        {
            // version 3
            if (temp.size() > 0) // 这里是父子进程继承时会出现的问题
            {
                for (const auto fd : temp)
                {
                    close(fd);
                }
            }
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            Work();
            exit(0);
        }

        close(pipefd[0]);
        channals->push_back({pipefd[1], id, i});
        temp.push_back(pipefd[1]);
    }
}

void PerformTasks(const vector<Channals> &c, bool flag, int task_num = -1)
{

    int pos = 0;
    while (true)
    {
        // 1. 生成任务编号
        int mession = task.GetTaskNum();
        // 2.选取信道, 并分配任务
        pos %= c.size();
        // 分配信道给任务
        cout << "Assign tasks: " << task.GetTaskName(mession) << "to channels: "
             << c[pos]._name << " worker: " << c[pos]._workid << endl;
        write(c[pos]._cntfd, &mession, sizeof(mession));
        //sleep(1);

        if (!flag)
        {
            if (task_num <= 0)
                break;
            task_num--;
        }

        pos++;
    }

    cout << "task assignment completed" << endl;
}

void ReleaseChildProcess(const vector<Channals> &c)
{
    // version 1 第一种版本关闭写入端直接结束子进程，后统一回收进程
    // for(const auto& channal: c)// 1. 让进程退出（利用管道情况，写入端关闭子进程结束）
    // {
    //     close(channal._cntfd);
    // }
    // for (int i = 0; i < c.size(); i++) //回收子进程
    // {
    //     int wret = waitpid(c[i]._workid, nullptr, 0);
    //     if (wret == c[i]._workid)
    //     {
    //         cout << "wait child( " <<wret << " ) success..." << endl;
    //     }
    // }

    // version 2 倒着 关闭写段fd
    // for (int i = c.size() - 1; i >= 0; i--) // 回收子进程
    // {
    //     close(c[i]._cntfd);

    //     int wret = waitpid(c[i]._workid, nullptr, 0);
    //     if (wret == c[i]._workid)
    //     {
    //         cout << "wait child( " << wret << " ) success..." << endl;
    //     }
    // }
    //  version 3 在创建管道以及子进程时将前面所有子进程创建好的写段fd拷贝到当前子进程后都关闭
    for (const auto &channal : c) // 1. 让进程退出（利用管道情况，写入端关闭子进程结束）
    {
        close(channal._cntfd);
        int wret = waitpid(channal._workid, nullptr, 0);
        if (wret == channal._workid)
        {
            cout << "wait child( " << wret << " ) success..." << endl;
        }
    }
}

int main()
{
    bool alwaysdo = true;
    vector<Channals> channals;
    CreateChannals(&channals);

    PerformTasks(channals, !alwaysdo, 1000);
    // PerformTasks(channals, alwaysdo);
    //PerformTasks(channals, !alwaysdo, 10);

    //sleep(100);
    ReleaseChildProcess(channals);

    return 0;
}